package com.ryl.yomall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ryl.yomall.model.common.cache.YomallCache;
import com.ryl.yomall.model.common.constant.RedisConst;
import com.ryl.yomall.model.product.BaseCategoryView;
import com.ryl.yomall.model.product.SkuImage;
import com.ryl.yomall.model.product.SkuInfo;
import com.ryl.yomall.model.product.SpuSaleAttr;
import com.ryl.yomall.product.mapper.*;
import com.ryl.yomall.product.service.ProductService;
import net.bytebuddy.build.ToStringPlugin;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Date 20:31
 * @Author ryl
 */
@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private BaseCategoryViewMapper baseCategoryViewMapper;
    @Autowired
    private SkuInfoMapper skuInfoMapper;
    @Autowired
    private SkuImageMapper skuImageMapper;
    @Autowired
    private SpuSaleAttrMapper spuSaleAttrMapper;
    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Override
    @YomallCache(prefix = "getBaseCategoryView")
    public BaseCategoryView getBaseCategoryView(Long category3Id) {
        return baseCategoryViewMapper.selectById ( category3Id );
    }
    @Override
    @YomallCache(prefix = "getSkuInfo")
    public SkuInfo getSkuInfo(Long skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectById ( skuId );
        if (skuInfo != null) {
            QueryWrapper<SkuImage> queryWrapper = new QueryWrapper ( );
            queryWrapper.eq ( "sku_id" ,skuId );
            List<SkuImage> skuImages = skuImageMapper.selectList ( queryWrapper );
            skuInfo.setSkuImageList ( skuImages );
        }
        return skuInfo;
    }
 /*   @Override
    public SkuInfo getSkuInfo(Long skuId)  {
        // 1.定义缓存中key
        String cacheKey = RedisConst.SKUKEY_PREFIX+skuId+RedisConst.SKUKEY_SUFFIX;
        String lockKey =RedisConst.SKUKEY_PREFIX+skuId+RedisConst.SKULOCK_SUFFIX;
        //从redis中去取值
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue ( ).get ( cacheKey );
        RLock rlock = redissonClient.getLock ( lockKey );
        if(skuInfo == null){
            //参数1: 过期不候 拿锁的时间 1S
            //参数2 让锁什么时候过期
            try {
                boolean lock = rlock.tryLock ( 1 ,1 ,TimeUnit.SECONDS );
                if(lock){
                    try {
                        skuInfo = getSkuInfoDB ( skuId );
                        if(skuInfo != null){
                            //保存缓存中
                            redisTemplate.opsForValue().set(cacheKey, skuInfo,
                                    RedisConst.SKUKEY_TIMEOUT + new Random ().nextInt(300)
                                    , TimeUnit.SECONDS);
                        }else{
                            // 保存缓存中一份  空结果也进行缓存，但它的过期时间会很短，最长不超过五分钟。
                            skuInfo=new SkuInfo ();
                            redisTemplate.opsForValue().set(cacheKey, skuInfo,
                                    5
                                    , TimeUnit.MINUTES);
                        }
                    } finally {
                        rlock.unlock ();
                    }

                }else{
                    //锁让别人拿走了
                    //查询缓存
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
                }

            } catch (InterruptedException e) {
                e.printStackTrace ( );
            }
        }
        return skuInfo;
    }*/
//底层实现
/*    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        // 1.定义缓存中key
        String cacheKey = RedisConst.SKUKEY_PREFIX+skuId+RedisConst.SKUKEY_SUFFIX;
        String lockKey =RedisConst.SKUKEY_PREFIX+skuId+RedisConst.SKULOCK_SUFFIX;
        //从redis中去取值
        SkuInfo skuInfo = (SkuInfo) redisTemplate.opsForValue ( ).get ( cacheKey );
        if(skuInfo == null){
            String uuid= UUID.randomUUID ().toString ();
            Boolean lock = redisTemplate.opsForValue ( ).setIfAbsent ( lockKey ,uuid ,2 ,TimeUnit.SECONDS );
            //拿到锁
            if(lock){
                skuInfo = getSkuInfoDB ( skuId );
                if(skuInfo != null){
                    //保存缓存中
                    redisTemplate.opsForValue().set(cacheKey, skuInfo,
                            RedisConst.SKUKEY_TIMEOUT + new Random ().nextInt(300)
                            , TimeUnit.SECONDS);
                }else{
                   // 保存缓存中一份  空结果也进行缓存，但它的过期时间会很短，最长不超过五分钟。
                    skuInfo=new SkuInfo ();
                    redisTemplate.opsForValue().set(cacheKey, skuInfo,
                            5
                            , TimeUnit.MINUTES);
                }
                //删除锁 原子性操作
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return tostring(redis.call('del',KEYS[1])) else return 0 end";
                this.redisTemplate.execute(new DefaultRedisScript<> (script), Collections.singletonList(lockKey), uuid);
            }else {
                //锁被别人拿了
                //查询缓存
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return (SkuInfo) redisTemplate.opsForValue().get(cacheKey);
            }

        }
        return  skuInfo;
    }*/
    /**
     * 将查询SkuInfo 去查询数据库封装
     */
/*    public SkuInfo getSkuInfoDB(Long skuId){
        SkuInfo skuInfo = skuInfoMapper.selectById ( skuId );
        if(skuInfo != null){
            QueryWrapper<SkuImage> queryWrapper=new QueryWrapper (  );
            queryWrapper.eq ( "sku_id",skuId );
            List<SkuImage> skuImages = skuImageMapper.selectList ( queryWrapper );
            skuInfo.setSkuImageList ( skuImages );
        }
        return skuInfo;
    }*/



    /**
     * 查询价格,不可以优化到缓存,只能实时更新
     */
    @Override
    public BigDecimal getPrice(Long skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectById ( skuId );

        if(skuInfo!=null){
            return skuInfo.getPrice ();
        }
        return new BigDecimal("0");
    }

    /**
     * 获取商品的销售属性和销售属性值集合,并选中sku_id
     */
    @Override
    @YomallCache(prefix = "getSpuSaleAttrAndChecked")
    public List<SpuSaleAttr> getSpuSaleAttrAndChecked(Long spuId ,Long skuId) {
        return spuSaleAttrMapper.getSpuSaleAttrAndChecked(spuId,skuId);
    }

    @Override
    @YomallCache(prefix = "getSaleAttrValuesBySpu")
    public Map getSaleAttrValuesBySpu(Long spuId) {
       Map result=new HashMap (  );
       List<Map> list=skuSaleAttrValueMapper.getSaleAttrValuesBySpu(spuId);
       list.forEach ( map -> {
           result.put (map.get ( "value_id" ),map.get ( "sku_id" )  );
       } );

     return result;

    }

    @Override
    public List<BaseCategoryView> getBaseCategoryViewList() {

       return  baseCategoryViewMapper.selectList ( null );
    }
}
